//
// This software is now distributed according to
// the Lesser Gnu Public License. Please see
// http://www.gnu.org/copyleft/lesser.txt for
// the details.
// -- Happy Computing!
//
package com.stevesoft.pat;

import java.util.Hashtable;

/**
 * If Multi were not split into a second stage, then a nested Multi would try to
 * re-use the same count variable and the whole thing would break.
 */
class Multi_stage2 extends PatternSub {

	Pattern nextRet;
	patInt count;
	patInt matchMin, matchMax;
	public boolean matchFewest = false;

	public String toString() {
		String ret = "";
		ret += sub.toString();
		ret += "{" + matchMin + "," + matchMax + "}";
		if (matchFewest)
			ret += "?";
		ret += parent.nextString();
		return ret;
	}

	Multi_stage2(patInt a, patInt b, Pattern p) throws RegSyntax {
		if (p == null)
			RegSyntaxError.endItAll("Multiple match of Null pattern requested.");
		sub = p;
		nextRet = this;
		sub.setParent(this);
		matchMin = a;
		matchMax = b;
		count = new patInt(0);
		// we must have b > a > -1 for this
		// to make sense.
		if (!a.lessEq(b))
			// throw new BadMultiArgs();
			RegSyntaxError.endItAll("Bad Multi Args: " + a + ">" + b);
		patInt i = new patInt(-1);
		if (a.lessEq(i))
			// throw new BadMultiArgs();
			RegSyntaxError.endItAll("Bad Multi Args: " + a + "< 0");
	}

	public Pattern getNext() {
		return nextRet;
	}

	int pos_old = -1;

	public int matchInternal(int pos, Pthings pt) {
		sub.setParent(this);
		int canUse = -1;
		// check for some forms of infinite recursion...
		if (pos_old >= 0 && pos == pos_old) {
			return -1;
		}
		pos_old = pos;
		if (matchMin.lessEq(count))
			canUse = pos;
		if (!count.lessEq(matchMax) || pos > pt.src.length())
			return -1;
		if ((matchFewest || count.equals(matchMax)) && canUse >= 0) {
			Pattern n = super.getNext();
			if (n == null)
				return canUse;
			int ret = testMatch(n, pos, pt);
			if (ret >= 0) {
				return ret;
			}
			else
				canUse = -1;
		}
		count.inc();
		try {
			if (count.lessEq(matchMax)) {
				int r = testMatch(sub, pos, pt);
				if (r >= 0)
					return r;
			}
		} finally {
			count.dec();
		}
		if (!matchFewest && canUse >= 0) {
			Pattern n = super.getNext();
			if (n == null)
				return canUse;
			int ret = testMatch(n, pos, pt);
			return ret;
		}
		else
			return canUse;
	}

	public Pattern clone1(Hashtable h) {
		try {
			Multi_stage2 m = new Multi_stage2(matchMin, matchMax, sub.clone(h));
			m.matchFewest = matchFewest;
			return m;
		} catch (RegSyntax rs) {
			return null;
		}
	}
};
